﻿using System;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ionic.Zip;
using System.Xml;
using System.Xml.Schema;
using System.Diagnostics;


namespace FennecUI
{
    class PackageManager
    {
        public static bool InstallPackage(String fileName)
        {
            string tempDir = GetTempDirectory();

            ZipFile package = new ZipFile(fileName);
            package.ExtractAll(tempDir);
            if (File.Exists(tempDir + @"\Applet.xml"))
            {
                //  XML validated against schema to ensure that it is the correct format
                XmlReaderSettings xrd = new XmlReaderSettings();
                xrd.Schemas.Add("http://code.google.com/p/touchswipe-dev/wiki/FennecAppletSchema", "FennecApplet.xsd");
                xrd.ValidationType = ValidationType.Schema;
                xrd.Schemas.Compile();

                XmlDocument xmlAppletDoc = new XmlDocument();
                XmlReader xmlAppletParser = XmlReader.Create(tempDir + @"\Applet.xml", xrd);
                try
                {
                    xmlAppletDoc.Load(xmlAppletParser);
                }
                catch (XmlSchemaValidationException)
                {
                    xmlAppletParser.Close();
                    Directory.Delete(tempDir,true);
                    return false;
                }
                xmlAppletParser.Close();

                //  Set up the xml Applet configuration file parser 
                XmlDocument xmlSettingsDoc = new XmlDocument();
                XmlReader xmlSettingsParser = XmlReader.Create(Configuration.APPLET_CONFIGURATION_FILE, xrd);
                xmlSettingsDoc.Load(xmlSettingsParser);
                xmlSettingsParser.Close();

                if (xmlAppletDoc.SchemaInfo.Validity == XmlSchemaValidity.Valid && xmlAppletDoc.DocumentElement.Name == "AppletInstallationPackage")
                {
                    XmlNode InstallationProcess = xmlAppletDoc.DocumentElement["InstallProcess"];
                    XmlNode UninstallationProcess = xmlAppletDoc.DocumentElement["UnInstallProcess"];
                    XmlNode AppletDefinition = xmlAppletDoc.DocumentElement["Applet"];
                    AppletConfiguration appletConfig = AppletConfiguration.FromXML(AppletDefinition);

                    Directory.CreateDirectory(e(@"%APPLETS_STORE%\" + appletConfig.Name));
                    Environment.SetEnvironmentVariable("APPLET_DIR", e(@"%APPLETS_STORE%\" + appletConfig.Name));
                    Environment.SetEnvironmentVariable("PACKAGE_TEMP", tempDir);

                    foreach (XmlNode n in InstallationProcess.ChildNodes)
                    {
                        switch (n.Attributes["type"].Value)
                        {
                            case CopyFile:
                                File.Copy(e(n.InnerText.Split(';')[0]), e(n.InnerText.Split(';')[1]), true);
                                break;
                            case CopyFolder:
                                CopyDir(e(n.InnerText.Split(';')[0]), e(n.InnerText.Split(';')[1]));
                                break;
                            case ExecuteInstaller:
                                Process p = new Process();
                                ProcessStartInfo pinfo = new ProcessStartInfo(e(n.InnerText.Split(';')[0]), e(n.InnerText.Split(';')[1]));
                                p.StartInfo = pinfo;
                                p.Start();
                                p.WaitForExit();
                                break;
                            case DeleteFile:
                                if (e(n.InnerText.Split(';')[1]) != "")
                                {
                                    if (MessageBox.Show(n.InnerText.Split(';')[1], "Confirm Deletion", MessageBoxButtons.YesNo) == DialogResult.Yes)
                                        File.Delete(e(n.InnerText.Split(';')[0]));
                                }
                                else
                                {
                                    File.Delete(e(n.InnerText.Split(';')[0]));
                                }
                                break;
                            case DeleteFolder:
                                if (e(n.InnerText.Split(';')[1]) != "")
                                {
                                    if (MessageBox.Show(n.InnerText.Split(';')[1], "Confirm Deletion", MessageBoxButtons.YesNo) == DialogResult.Yes)
                                        Directory.Delete(e(n.InnerText.Split(';')[0]));
                                }
                                else
                                {
                                    Directory.Delete(e(n.InnerText.Split(';')[0]));
                                }
                                break;
                        }
                    }

                    File.Copy(tempDir + @"\Applet.xml", e(@"%APPLET_DIR%\Applet.xml"), true);
                    Directory.Delete(tempDir,true);

                    AppletDefinition = xmlSettingsDoc.ImportNode(AppletDefinition, true);
                    xmlSettingsDoc.DocumentElement.AppendChild(AppletDefinition);
                    xmlSettingsDoc.Save(Configuration.APPLET_CONFIGURATION_FILE);

                    return true;
                }
                else
                    return false;
            }

            return false;
        }

        private const string CopyFile = "CopyFile";
        private const string CopyFolder = "CopyFolder";
        private const string ExecuteInstaller = "ExecuteInstaller";
        private const string DeleteFile = "DeleteFile";
        private const string DeleteFolder = "DeleteFolder";

        private static string e(string value)
        {
            return Environment.ExpandEnvironmentVariables(value);
        }

        private static string GetTempDirectory()
        {
            string path = Path.GetRandomFileName();
            path = Path.Combine(Path.GetTempPath(), path);
            Directory.CreateDirectory(path);
            return path;
        }

        private static void CopyDir(String sourceDir, String targetDir)
        {
            DirectoryInfo source = new DirectoryInfo(sourceDir);
            DirectoryInfo target = new DirectoryInfo(targetDir);
            if (source.FullName.ToLower() == target.FullName.ToLower())
            {
                return;
            }

            // Check if the target directory exists, if not, create it.
            if (Directory.Exists(target.FullName) == false)
            {
                Directory.CreateDirectory(target.FullName);
            }

            // Copy each file into it's new directory.
            foreach (FileInfo fi in source.GetFiles())
            {
                fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
            }

            // Copy each subdirectory using recursion.
            foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
            {
                DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
                CopyDir(diSourceSubDir.FullName, nextTargetSubDir.FullName);
            }
        }


    }
}
